#include <xscript/xitemlist.h>
#include <xscript/xitemdict.h>
#include <astree/xabstractsyntaxtreebuilder.h>
#include <astree/xabstractsynatxtreeblock.h>
#include <astree/xabstractsyntaxtreevalue.h>
#include <astree/xabstractsyntaxtreebuilderimpl.h>
#include <astree/xabstractsyntaxtreearithmetic.h>
#include <astree/xabstractsyntaxtreecompare.h>
#include <astree/xabstractsyntaxtreepunctuator.h>
#include <astree/xabstractsyntaxtreelet.h>
#include <astree/xabstractsyntaxtreevalue.h>
#include <astree/xabstractsyntaxtreecreator_let.h>
#include <astree/xabstractsyntaxtreecreator_assign.h>
#include <astree/xabstractsyntaxtreecreator_print.h>

bool XAbstractSyntaxTreeCreator::isMatched(const XTokenBlock& tokens, uint32_t row, uint32_t col) {
    if (tokens.size() > row && tokens.at(row).tokens.size() > col)
        return tokens.at(row).tokens.at(col)->getString() == getName();
    return false;
}

XAbstractSyntaxTreeBuilder::XAbstractSyntaxTreeBuilder() {
    setName(L"XAbstractSyntaxTreeBuilder");

    registerCreate(std::make_shared<XAbstractSyntaxTreeCreator_Let>(L"let"));
    //registerCreate(std::make_shared<XAbstractSyntaxTreeCreator_Assign>(L"assign"));
    registerCreate(std::make_shared<XAbstractSyntaxTreeCreator_Print>(L"print"));

    //registerCreate(std::make_shared<XAbstractSyntaxTreeCreatorVariable>());

    /*
    registerCreate(std::make_shared<XAbstractSyntaxTreeCreatorInt>());
    registerCreate(std::make_shared<XAbstractSyntaxTreeCreatorFloat>());

    registerCreate(std::make_shared<XAbstractSyntaxTreeCreator_Generic<XAbstractSyntaxTreePlus>>(L"+"));
    registerCreate(std::make_shared<XAbstractSyntaxTreeCreator_Generic<XAbstractSyntaxTreeMinus>>(L"-"));
    registerCreate(std::make_shared<XAbstractSyntaxTreeCreator_Generic<XAbstractSyntaxTreeMulti>>(L"*"));
    registerCreate(std::make_shared<XAbstractSyntaxTreeCreator_Generic<XAbstractSyntaxTreeDiv>>(L"/"));
    registerCreate(std::make_shared<XAbstractSyntaxTreeCreator_Generic<XAbstractSyntaxTreeGreate>>(L">"));
    registerCreate(std::make_shared<XAbstractSyntaxTreeCreator_Generic<XAbstractSyntaxTreeGreateOrEqual>>(L">="));
    registerCreate(std::make_shared<XAbstractSyntaxTreeCreator_Generic<XAbstractSyntaxTreeLess>>(L"<"));
    registerCreate(std::make_shared<XAbstractSyntaxTreeCreator_Generic<XAbstractSyntaxTreeLessOrEqual>>(L"<="));
    registerCreate(std::make_shared<XAbstractSyntaxTreeCreator_Generic<XAbstractSyntaxTreeAnd>>(L"and"));
    registerCreate(std::make_shared<XAbstractSyntaxTreeCreator_Generic<XAbstractSyntaxTreeNot>>(L"not"));
    registerCreate(std::make_shared<XAbstractSyntaxTreeCreator_Generic<XAbstractSyntaxTreeOr>>(L"or"));
    registerCreate(std::make_shared<XAbstractSyntaxTreePunctuatorOpenBrace>());
    registerCreate(std::make_shared<XAbstractSyntaxTreePunctuatorCloseBrace>());
    registerCreate(std::make_shared<XAbstractSyntaxTreePunctuatorOpenBracket>());
    registerCreate(std::make_shared<XAbstractSyntaxTreePunctuatorCloseBracket>());
    registerCreate(std::make_shared<XAbstractSyntaxTreePunctuatorOpenParenthesis>());
    registerCreate(std::make_shared<XAbstractSyntaxTreePunctuatorCloseParenthesis>());
    */
}

std::shared_ptr<XAbstractSyntaxTree> XAbstractSyntaxTreeBuilder::build(const XTokenBlock& tokens) {
    skipToRow = skipToCol = 0;

    assert(!tokens.empty());

    std::shared_ptr<XAbstractSyntaxTreeBlock> block = std::make_shared<XAbstractSyntaxTreeBlock>(tokens.at(0).tokens.at(0));

    auto itr = creators.begin();
    while (itr != creators.end()) {
        auto creator = *itr;
        if (creator->isMatched(tokens, skipToRow, skipToCol)) {
            //print(std::wcout, "current row", skipToRow);
            auto ast = creator->create(tokens, skipToRow, skipToCol, shared_from_this());
            if (ast) {
                block->addChild(ast);

                skipToRow = creator->getSkipToRow();
                skipToCol = creator->getSkipToCol();

                if (skipToRow >= tokens.size())
                    break;
                else {
                    itr = creators.begin();
                    continue;
                }
            } else
                return nullptr;
        }
        itr ++;
    }

    assert(stack.empty());
    return block;
}

void XAbstractSyntaxTreeBuilder::onReceivedPunctuatorOpenBrace(std::shared_ptr<XAbstractSyntaxTree> tree) {

}

void XAbstractSyntaxTreeBuilder::onReceivedPunctuatorCloseBrace(std::shared_ptr<XAbstractSyntaxTree> tree) {

}

void XAbstractSyntaxTreeBuilder::onReceivedPunctuatorOpenParenthesis(std::shared_ptr<XAbstractSyntaxTree> tree) {

}

void XAbstractSyntaxTreeBuilder::onReceivedPunctuatorCloseParenthesis(std::shared_ptr<XAbstractSyntaxTree> tree) {

}

void XAbstractSyntaxTreeBuilder::onReceivedPunctuatorOpenBracket(std::shared_ptr<XAbstractSyntaxTree> tree) {
    if (stack.empty()) {

    } else {
        auto top = stack.top();
        if (top->getName() == L"=")
            ;//stack.push(std::make_shared<XAbstractSyntaxTreeList>());
    }

}

void XAbstractSyntaxTreeBuilder::onReceivedPunctuatorCloseBracket(std::shared_ptr<XAbstractSyntaxTree> tree) {

}






